package com.zijidelu.luframework.infrastructure.persistence.repository.core.domain;

import com.zijidelu.luframework.base.model.DataModel;
import com.zijidelu.luframework.base.model.PO;
import com.zijidelu.luframework.base.model.crud.CrudState;
import com.zijidelu.luframework.domain.exception.RepositoryException;
import com.zijidelu.luframework.domain.model.aggregate.AggregateRoot;
import com.zijidelu.luframework.domain.model.entity.Entity;
import com.zijidelu.luframework.infrastructure.converter.DataConverter;
import com.zijidelu.luframework.infrastructure.factory.ConverterVault;
import com.zijidelu.luframework.infrastructure.factory.DataVault;
import com.zijidelu.luframework.infrastructure.persistence.repository.core.data.DataRepository;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 聚合执行计划
 *
 * @author ZIJIDELU
 * @datetime 2025/11/27 16:28
 */
public class AggregateExecutionPlan<D extends DataModel, E extends Entity<D>, A extends AggregateRoot<D, E>> {
    private final Collection<A> aggregateRoots;
    private final Class<D> rootDataModelClass;
    private final List<D> rootCreateList = new ArrayList<>();
    private final List<D> rootUpdateList = new ArrayList<>();
    private final List<D> rootDeleteList = new ArrayList<>();
    private final List<D> rootReadList = new ArrayList<>();
    /**
     * 执行器，需要根实体执行完成后，才能执行
     */
    private final List<Runnable> postRootCreateRunnableList = new ArrayList<>();
    private final List<DataModel> childrenCreateList = new ArrayList<>();
    private final List<DataModel> childrenUpdateList = new ArrayList<>();
    private final List<DataModel> childrenDeleteList = new ArrayList<>();
    private final List<DataModel> childrenReadList = new ArrayList<>();

    private AggregateExecutionPlan(Collection<A> aggregateRoots, Class<D> rootDataModelClass) {
        this.aggregateRoots = aggregateRoots;
        this.rootDataModelClass = rootDataModelClass;
        prepare();
    }

    /**
     * 创建聚合执行计划
     *
     * @param aggregateRoots     聚合根集合
     * @param rootDataModelClass 根数据模型类
     * @param <D>                根数据模型类型
     * @param <E>                实体类型
     * @param <A>                聚合根类型
     * @return 聚合执行计划
     */
    public static <D extends DataModel, E extends Entity<D>, A extends AggregateRoot<D, E>> AggregateExecutionPlan<D, E, A> of(Collection<A> aggregateRoots, Class<D> rootDataModelClass) {
        if (aggregateRoots == null || aggregateRoots.isEmpty()) {
            throw new IllegalArgumentException("aggregateRoots is null or empty");
        }

        if (rootDataModelClass == null) {
            throw new IllegalArgumentException("rootDataModelClass is null");
        }

        return new AggregateExecutionPlan<>(aggregateRoots, rootDataModelClass);
    }

    /**
     * 检查操作结果是否成功
     *
     * @param result    操作结果
     * @param operation 操作描述
     */
    private static void checkResult(boolean result, String operation) {
        if (!result) {
            throw new RepositoryException("Failed to " + operation + ".");
        }
    }

    private void prepare() {
        for (A aggregateRoot : aggregateRoots) {
            if (aggregateRoot == null) {
                continue;
            }

            final E rootEntity = aggregateRoot.getRootEntity();
            if (rootEntity == null) {
                continue;
            }

            final CrudState crudState = rootEntity.getCrudState();
            final D dataModel = rootEntity.asDataModel();
            // 分组父实体
            switch (crudState) {
                case CREATE -> rootCreateList.add(dataModel);
                case UPDATE -> rootUpdateList.add(dataModel);
                case DELETE -> rootDeleteList.add(dataModel);
                case READ -> rootReadList.add(dataModel);
            }

            // 创建
            aggregateRoot.getChildrenEntityVault().getCreatedList().forEach(e -> {
                childrenCreateList.add(e.asDataModel());
                postRootCreateRunnableList.add(() -> e.setRootEntityId(dataModel.getId()));
            });
            // 更新
            childrenUpdateList.addAll(aggregateRoot.getChildrenEntityVault().getUpdatedList().stream().map(Entity::asDataModel).toList());
            // 删除
            childrenDeleteList.addAll(aggregateRoot.getChildrenEntityVault().getDeletedList().stream().map(Entity::asDataModel).toList());
            // 读取
            childrenReadList.addAll(aggregateRoot.getChildrenEntityVault().getReadList().stream().map(Entity::asDataModel).toList());
        }

    }

    /**
     * 执行加载操作
     *
     * @param dataVault      数据仓库
     * @param converterVault 数据转换器
     */
    public void executeLoad(DataVault dataVault, ConverterVault converterVault) {
        for (A aggregateRoot : aggregateRoots) {
            aggregateRoot.prepareLoad();
        }

        // 加载父实体
        final DataRepository<PO, D> dataRepository = dataVault.getDataRepository(rootDataModelClass);
        final DataConverter<PO, DataModel> dataConverter = converterVault.getDataConverter(rootDataModelClass);
        if (!rootReadList.isEmpty()) {
            // 构建ID-数据模型映射
            final Map<Serializable, D> rootReadMap = rootReadList.stream().collect(Collectors.toMap(DataModel::getId, d -> d));
            // 加载数据库中的数据模型
            final List<D> dataModelsByPersist = dataRepository.findBatchById(rootReadMap.keySet());
            for (D dataModelByID : dataModelsByPersist) {
                // 获取映射中的数据模型
                final D data = rootReadMap.get(dataModelByID.getId());
                if (data == null) {
                    continue;
                }

                // 复制数据到父实体
                dataConverter.copyData(dataModelByID, data);
            }
        }

        // 加载子实体
        if (!childrenReadList.isEmpty()) {
            // 构建ID-数据模型映射
            final Map<Serializable, DataModel> childrenReadMap = childrenReadList.stream().collect(Collectors.toMap(DataModel::getId, d -> d));
            // 加载数据库中的子实体数据模型
            final List<DataModel> childrenReadListByPersist = new ArrayList<>();
            childrenReadList.stream().collect(Collectors.groupingBy(DataModel::getClass))
                    .forEach((clazz, dataModelList) -> {
                        // 获取子实体数据模型的数据仓库
                        DataRepository<PO, DataModel> dataRepositoryByObject = dataVault.getDataRepositoryFor(clazz);
                        // 加载数据库中的子实体数据模型
                        List<DataModel> dataModelByIdLIst = dataRepositoryByObject.findBatchById(dataModelList.stream().map(DataModel::getId).collect(Collectors.toSet()));
                        childrenReadListByPersist.addAll(dataModelByIdLIst);
                    });

            for (DataModel dataModelByID : childrenReadListByPersist) {
                // 获取映射中的子实体数据模型
                final DataModel data = childrenReadMap.get(dataModelByID.getId());
                if (data == null) {
                    continue;
                }

                // 复制数据到子实体
                converterVault.getDataConverter(data.getClass()).copyData(dataModelByID, data);
            }

        }
    }

    /**
     * 执行持久化操作
     *
     * @param dataVault 数据仓库
     */
    public void executePersist(DataVault dataVault) {
        for (A aggregateRoot : aggregateRoots) {
            aggregateRoot.preparePersist();
        }

        final DataRepository<PO, D> dataRepository = dataVault.getDataRepository(rootDataModelClass);
        // 保存父实体
        if (!rootCreateList.isEmpty()) {
            boolean saveBatchResult = dataRepository.saveBatch(rootCreateList);
            checkResult(saveBatchResult, "save root entities");
        }
        // 更新父实体
        if (!rootUpdateList.isEmpty()) {
            boolean updateBatchResult = dataRepository.updateBatchById(rootUpdateList);
            checkResult(updateBatchResult, "update root entities");
        }
        // 删除父实体
        if (!rootDeleteList.isEmpty()) {
            boolean deleteBatchResult = dataRepository.deleteBatchById(rootDeleteList.stream().map(DataModel::getId).toList());
            checkResult(deleteBatchResult, "delete root entities");
        }

        // 执行后续操作
        if (!postRootCreateRunnableList.isEmpty()) {
            postRootCreateRunnableList.forEach(Runnable::run);
        }

        // 保存子实体
        if (!childrenCreateList.isEmpty()) {
            childrenCreateList.stream().collect(Collectors.groupingBy(DataModel::getClass))
                    .forEach((clazz, dataModelList) -> {
                        boolean saveBatchResult = dataVault.getDataRepositoryFor(clazz).saveBatch(dataModelList);
                        checkResult(saveBatchResult, "save children entities");
                    });
        }
        // 更新子实体
        if (!childrenUpdateList.isEmpty()) {
            childrenUpdateList.stream().collect(Collectors.groupingBy(DataModel::getClass))
                    .forEach((clazz, dataModelList) -> {
                        boolean updateBatchResult = dataVault.getDataRepositoryFor(clazz).updateBatchById(dataModelList);
                        checkResult(updateBatchResult, "update children entities");
                    });
        }
        // 删除子实体
        if (!childrenDeleteList.isEmpty()) {
            childrenDeleteList.stream().collect(Collectors.groupingBy(DataModel::getClass))
                    .forEach((clazz, dataModelList) -> {
                        boolean deleteBatchResult = dataVault.getDataRepositoryFor(clazz).deleteBatchById(dataModelList.stream().map(DataModel::getId).collect(Collectors.toSet()));
                        checkResult(deleteBatchResult, "delete children entities");
                    });
        }
    }
}
